package tech.yixiyun.framework.kuafu.kits;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.RandomUtil;
import io.jsonwebtoken.*;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.Serializable;
import java.security.SignatureException;
import java.util.Date;
import java.util.UUID;

public class JWTKit {

    /**
     * 超时 1天
     */
    public static final int EXPIRE_1_DAY = 86400;

    /**
     * 超时1小时
     */
    public static final int EXPRIE_1_HOUR = 3600;
    /**
     * 超时2小时
     */
    public static final int EXPRIE_2_HOUR = 7200;

    /**
     * 超时1分钟
     */
    public static final int EXPIRE_1_MINITE = 60;
    /**
     * 超时10分钟
     */
    public static final int EXPIRE_10_MINITE = 600;
    /**
     * 超时15分钟
     */
    public static final int EXPIRE_15_MINITE = 900;
    /**
     * 超时30分钟
     */
    public static final int EXPRIE_30_MINITES = 1800;


    private static String SECRETKEY = RandomUtil.randomString(10);


    /**
     * 更新jwt加密使用的secretkey，一定要慎重调用该方法，调用后，之前生成的jwt都会失效，会导致所有用户需要重新鉴权。<br/>
     * 它适合
     * 1)类似 更新前要强制所有用户退出系统 这种场景使用。<br/>
     * 2)默认情况下，为了安全系统每次启动都会随机一个新的SECRETKEY，也就导致系统启动后，所有用户都要重新登录。如果不希望SecretKey随机，可以通过BootHandler 调用该方法set一个恒定的值
     * @param newKey
     */
    public static void updateSecretKey(String newKey) {
        SECRETKEY = newKey;
    }


    /**
     * 创建jwt
     * @param expireTime 过期时间，单位秒
     * @param data
     * @return
     */
    public static String createToken(int expireTime, Serializable... data) {
        if (data.length % 2 != 0) {
            throw new RuntimeException("传入的生成token参数数量不对，请按照key,value,key,value传入");
        }
        Kv o = Kv.of(data);
        return createTokenByKv(expireTime, o);
    }

    /**
     * 创建jwt
     * @param expireTime 过期时间，单位s
     * @param data 写入jwt的内容
     * @return jwt token
     * @throws Exception
     */
    public static String createTokenByKv(int expireTime, Kv data) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        SecretKey key = generalKey(SECRETKEY);
        JwtBuilder builder = Jwts.builder()
                .setIssuer("forward")//发行者
                .setId(UUID.randomUUID().toString())
                .setIssuedAt(now)
                .setSubject(JSONKit.toJson(data))
                .signWith(signatureAlgorithm, key);
        //超时 1天
        long expMillis = nowMillis + expireTime * 1000;
        Date exp = new Date(expMillis);
        builder.setExpiration(exp).setNotBefore(now);
        return builder.compact();
    }

    /**
     * 验证token，如果失效，就会返回null
     * @param token
     * @return
     */
    public static Kv verifyToken(String token) {
        SecretKey key = generalKey(SECRETKEY);
        try {
            Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody();
            return JSONKit.toObject(claims.getSubject(), Kv.class);


        } catch (Exception e) {
            return null;
        }
    }





    /**
     * 由字符串生成加密key
     *
     * @return
     */
    private static SecretKey generalKey(String stringKey) {
        byte[] encodedKey = Base64.decode(stringKey);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    /**
     * 解密jwt，获取实体
     * @param jwt
     */
    private static Claims parseJWT(String jwt) throws ExpiredJwtException, UnsupportedJwtException,
            MalformedJwtException, SignatureException, IllegalArgumentException {
        SecretKey key = generalKey(SECRETKEY);
        Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(jwt).getBody();
        return claims;
    }


}
